﻿#include <iostream>
#include <opencv2/opencv.hpp>
#include <filesystem>

using namespace cv;
using namespace std;
namespace fs = std::filesystem;

int main()
{
	// 获取当前可执行文件的路径
	fs::path exePath = fs::current_path();
	// 构建资源文件的完整路径
	fs::path imagePath = exePath / "x64\\Debug\\img\\C++.png";
	string imgPath_str = imagePath.generic_string();

	//OpenCV（Open Source Computer Vision Library）是一个开源的计算机视觉和机器学习软件库

	//加载图片: 图片路径、读取图像的方式
	Mat image = imread(imgPath_str, IMREAD_COLOR);
	//可调整窗体大小
	//namedWindow("图片显示窗口", WINDOW_FREERATIO);

	if (image.empty())
	{
		cout << "没有图像\n";
		return -1;
	}
	//显示图像
	imshow("原图片窗口", image);


	//均值滤波是一种简单的线性滤波方法，它将图像中每个像素的值替换为其邻域内所有像素值的平均值。
	//这种方法可以有效去除噪声，但也会使图像变得模糊。
	cv::Mat src = cv::imread(imgPath_str, cv::IMREAD_GRAYSCALE);
	cv::Mat dst;
	cv::blur(src, dst, cv::Size(3, 3));  // 3x3的均值滤波
	//显示图像
	imshow("均值滤波窗口", dst);



	//高斯滤波是一种非线性滤波方法，它使用高斯函数来计算邻域内像素的权重，
	//从而对图像进行平滑处理。高斯滤波在去除噪声的同时，能够更好地保留图像的边缘信息。
	cv::GaussianBlur(src, dst, cv::Size(5, 5), 0);  // 5x5的高斯滤波
	//显示图像
	imshow("高斯滤波窗口", dst);


	//中值滤波是一种非线性滤波方法，它将图像中每个像素的值替换为其邻域内所有像素值的中值。
	//这种方法在去除椒盐噪声时效果非常好。
	cv::medianBlur(src, dst, 5);  // 5x5的中值滤波
	//显示图像
	imshow("中值滤波窗口", dst);



	//OpenCV允许用户自定义滤波器核，通过cv::filter2D函数可以实现自定义滤波操作。
	cv::Mat kernel = (cv::Mat_<float>(3, 3) << 1, 0, -1, 0, 0, 0, -1, 0, 1);
	cv::filter2D(src, dst, -1, kernel);
	//显示图像
	imshow("自定义滤波器核窗口", dst);


	/*
	边缘检测是图像处理中的一个重要任务，用于识别图像中物体的边界。
	常用的边缘检测方法包括Sobel算子和Canny边缘检测。

	Sobel算子是一种基于梯度的边缘检测方法，它可以检测图像中的水平和垂直边缘。
	Canny 边缘检测是一种多阶段的边缘检测算法，它能够有效地检测出图像中的边缘，并且对噪声具有较强的鲁棒性。
	*/

	//Sobel算子
	cv::Mat grad_x, grad_y;
	cv::Sobel(src, grad_x, CV_16S, 1, 0);  // 水平方向
	cv::Sobel(src, grad_y, CV_16S, 0, 1);  // 垂直方向
	cv::convertScaleAbs(grad_x, grad_x);
	cv::convertScaleAbs(grad_y, grad_y);
	cv::addWeighted(grad_x, 0.5, grad_y, 0.5, 0, dst);  // 合并结果
	//显示图像
	imshow("Sobel算子边缘检测窗口", dst);


	//Canny 边缘检测
	cv::Canny(src, dst, 100, 200);  // 阈值1=100，阈值2=200
	//显示图像
	imshow("Canny边缘检测窗口", dst);





	/*
	图像形态学操作
	形态学操作是基于图像形状的一系列操作，常用于图像的前景和背景分离、噪声去除等任务。
	常见的形态学操作包括腐蚀、膨胀、开运算、闭运算和形态学梯度。
	*/

	//腐蚀操作可以消除图像中的小物体或细节，使得前景物体变小。
	cv::Mat kernel2 = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
	cv::erode(src, dst, kernel2);
	//显示图像
	imshow("腐蚀操作窗口", dst);


	//膨胀操作可以扩大图像中的前景物体，常用于填补前景物体中的空洞。
	cv::dilate(src, dst, kernel2);
	//显示图像
	imshow("膨胀操作窗口", dst);



	//开运算是先腐蚀后膨胀的操作，常用于去除小物体或噪声。
	cv::morphologyEx(src, dst, cv::MORPH_OPEN, kernel2);
	//显示图像
	imshow("开运算窗口", dst);



	//闭运算是先膨胀后腐蚀的操作，常用于填补前景物体中的小孔。
	cv::morphologyEx(src, dst, cv::MORPH_CLOSE, kernel2);
	//显示图像
	imshow("闭运算窗口", dst);



	//形态学梯度是膨胀和腐蚀的差值，可以用于提取物体的边缘。
	cv::morphologyEx(src, dst, cv::MORPH_GRADIENT, kernel2);
	//显示图像
	imshow("形态学梯度窗口", dst);


	/*
	图像阈值化
	图像阈值化是将图像转换为二值图像的过程，常用于图像分割。常见的阈值化方法包括二值化、自适应阈值和Otsu阈值法。
	*/

	//二值化是将图像中的像素值根据设定的阈值分为两类，通常用于简单的图像分割。
	cv::threshold(src, dst, 127, 255, cv::THRESH_BINARY);
	//显示图像
	imshow("二值化窗口", dst);


	//自适应阈值根据图像的局部区域动态计算阈值，适用于光照不均匀的图像。
	cv::adaptiveThreshold(src, dst, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, 11, 2);
	//显示图像
	imshow("自适应阈值窗口", dst);



	//Otsu阈值法是一种自动确定阈值的方法，适用于双峰直方图的图像。
	cv::threshold(src, dst, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
	//显示图像
	imshow("Otsu阈值法窗口", dst);







	/*
	图像直方图
	直方图是图像处理中用于分析图像亮度分布的工具。常见的直方图操作包括计算直方图、直方图均衡化和直方图对比。
	*/

	//直方图可以反映图像中像素值的分布情况。
	cv::Mat hist;
	int histSize = 256;
	float range[] = { 0, 256 };
	const float* histRange = { range };
	cv::calcHist(&src, 1, 0, cv::Mat(), hist, 1, &histSize, &histRange);
	//显示图像
	imshow("直方图窗口", hist);



	//直方图均衡化可以增强图像的对比度，使得图像的亮度分布更加均匀。
	cv::equalizeHist(src, dst);
	//显示图像
	imshow("直方图均衡化窗口", dst);



	//直方图对比可以用于比较两幅图像的相似性。
	double compare = cv::compareHist(hist, dst, cv::HISTCMP_CORREL);
	cout << "直方图对比结果：" << compare << "\n";







	waitKey();
	return 0;
}